﻿using System; 
using System.Collections.Generic;
using System.Text; 
using UnityEngine;
using XFABManager;

namespace XFGameFramework.EquipmentSystem
{

    public enum EquipState 
    {
        /// <summary>
        /// 装备成功
        /// </summary>
        [Tooltip("装备成功")]
        Success,

        /// <summary>
        /// 当前游戏角色不能装备该装备
        /// </summary>
        [Tooltip("当前游戏角色不能装备该装备")]
        CannotEquip,

        /// <summary>
        /// 已经装备
        /// </summary>
        [Tooltip("已经装备")]
        AlreadyEquipped
    }

     
    /// <summary>
    /// 装备系统业务逻辑
    /// </summary>
    public class EquipmentManager
    {
        #region Config

        private static Dictionary<string, EquipmentsConfig> configs = new Dictionary<string, EquipmentsConfig>();

        /// <summary>
        /// 添加装备配表
        /// </summary>
        /// <param name="equipmentsConfig">装备配置</param>
        /// <exception cref="Exception">ID重复</exception>
        public static void AddConfig(EquipmentsConfig equipmentsConfig)
        {
            if (configs.ContainsKey(equipmentsConfig.name))
            {
                Debug.LogWarningFormat("已添加装备配置,请勿重复添加!");
                return;
            }

            foreach (var skill in equipmentsConfig.Equipments)
            {
                foreach (var config in configs.Values)
                {
                    if (config.GetEquipmentConfigData(skill.id) == null)
                        continue;

                    StringBuilder builder = new StringBuilder();
                    builder.Append("检测到装备id重复,");
                    builder.Append("配置:").Append(equipmentsConfig.name);
                    builder.Append("装备:").Append(skill.id).Append(skill.equipment_name);
                    builder.Append("配置:").Append(config.name);
                    builder.Append("装备:").Append(skill.id).Append(config.GetEquipmentConfigData(skill.id).equipment_name);

                    throw new Exception(builder.ToString());
                }
            }

            configs.Add(equipmentsConfig.name,equipmentsConfig);
        }

        /// <summary>
        /// 移除装备配表
        /// </summary>
        /// <param name="name">配表名称</param>
        public static void RemoveConfig(string name) 
        {
            EquipmentsConfig config = GetConfig(name);
            RemoveConfig(config);
        }

        /// <summary>
        /// 移除装备配表
        /// </summary>
        /// <param name="equipmentsConfig">配表对象</param>
        public static void RemoveConfig(EquipmentsConfig equipmentsConfig)
        {
            if (equipmentsConfig == null) return;

            if (configs.ContainsKey(equipmentsConfig.name))
                configs.Remove(equipmentsConfig.name);
        }

        /// <summary>
        /// 查询装备配表
        /// </summary>
        /// <param name="name">配表名称</param>
        /// <returns></returns>
        public static EquipmentsConfig GetConfig(string name) 
        {
            if(configs.ContainsKey(name))
                return configs[name]; 
            return null;
        }
        
        #endregion
          
        #region 方法

        /// <summary>
        /// 查询装备配置数据
        /// </summary>
        /// <param name="id">装备id</param>
        /// <returns></returns>
        public static EquipmentConfigData GetEquipmentInfo(int id)
        {
            foreach (var item in configs.Values)
            {
                EquipmentConfigData data = item.GetEquipmentConfigData(id);
                if (data == null) continue;
                return data;
            }

            return null;
        }



        /// <summary>
        /// 装备
        /// </summary>
        /// <param name="equipper">装备者(能够装备装备的游戏物体) </param>
        /// <param name="equipment">具体的某一个装备对象</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static EquipState Equip(IEquippable equipper, IEquipment equipment)
        {
            if (equipper == null)
                throw new Exception("equipper is null!");

            if (equipper.Equipments == null)
                throw new Exception("请初始化IEquippable.Equipments!");

            if (IsNull(equipment))
                throw new Exception("equipment is null!");

            if (equipper.Equipments.Contains(equipment))
                return EquipState.AlreadyEquipped;

            bool isCanEquip = equipper.IsCanEquip(equipment);

            if (isCanEquip)
            {
                equipper.Equipments.Add(equipment);
                equipment.Equiper = equipper;
                equipment.OnEquip();
                return EquipState.Success;
            }
            else 
            {
                return EquipState.CannotEquip;
            } 
        }

        /// <summary>
        /// 卸掉所有装备
        /// </summary>
        /// <param name="equipper">装备者(能够装备装备的游戏物体)</param>
        [Obsolete("已过时,请使用EquipmentManager.UnEquipAll代替!")]
        public static void UnEquip(IEquippable equipper)
        {
            UnEquipAll(equipper,true);
        }

        /// <summary>
        /// 卸掉所有装备
        /// </summary>
        /// <param name="equipper">装备者(能够装备装备的游戏物体)</param>
        /// <param name="destroy">是否回收装备</param>
        public static void UnEquipAll(IEquippable equipper,bool destroy = true)
        {
            if (IsNull(equipper)) return;

            for (int i = equipper.Equipments.Count - 1; i >= 0; i--)
            {
                UnEquip(equipper.Equipments[i], destroy);
            }
        }

        /// <summary>
        /// 卸掉某个装备
        /// </summary>
        /// <param name="equipper">目标</param>
        /// <param name="skillId">装备id</param>
        [Obsolete("已过时,请使用重载函数 UnEquip(IEquipment equipment , bool destroy = true) 代替!")]
        public static void UnEquip(IEquippable equipper, IEquipment equipment)
        {
            // 移除
            equipper.Equipments.Remove(equipment);
            if (IsNull( equipment )) return;
            equipment.OnUnEquip();

            switch (equipment.EquipmentData.equipmentType)
            {
                case EquipmentType.Asset:
                    equipment.OnUnloaded();
                    Component component = equipment as Component;
                    if (component != null)
                        GameObjectLoader.UnLoad(component.gameObject); 
                    break;
                case EquipmentType.Script:
                    ClassObjectPoolManager.Unload(equipment);
                    break;
            }

            equipment.Equiper = null;
            //equipment.EquipmentData = null;
        }

        /// <summary>
        /// 卸掉某个装备
        /// </summary>
        /// <param name="equipment"> </param>
        /// <param name="destroy"></param>
        public static void UnEquip(IEquipment equipment , bool destroy = true)
        { 
            if (IsNull(equipment)) return;
            // 移除
            if(!IsNull(equipment.Equiper))
                equipment.Equiper.Equipments.Remove(equipment);
            equipment.OnUnEquip();
            equipment.Equiper = null;

            if (destroy) 
                DestroyEquipmentInternal(equipment); 
        }

        private static bool IsNull(IEquipment equipment)
        {
            if(equipment == null) 
                return true;

            if (equipment is Component) 
            {
                Component component = (Component)equipment;
                if (component.IsDestroy())
                    return true;
            }

            return false;

        }

        private static bool IsNull(IEquippable equippable)
        {
            if (equippable == null)
                return true;

            if (equippable is Component)
            {
                Component component = (Component)equippable;
                if (component.IsDestroy())
                    return true;
            }

            return false;

        }

        /// <summary>
        /// 创建装备
        /// </summary>
        /// <param name="equipmentId">装备id</param>
        /// <returns>装备对象</returns>
        /// <exception cref="Exception"></exception>
        public static IEquipment CreateEquipment(int equipmentId) 
        {  
            EquipmentConfigData equipmentConfigData = GetEquipmentInfo(equipmentId);

            if (equipmentConfigData == null)
                throw new Exception(string.Format("装备:{0}配置信息查询失败!", equipmentId));

            IEquipment equipment = null;

            switch (equipmentConfigData.equipmentType)
            {
                case EquipmentType.Asset:
                    GameObject equipmentObj = GameObjectLoader.Load(equipmentConfigData.projectName, equipmentConfigData.assetName);

                    if (equipmentObj == null)
                        throw new Exception(string.Format("装备:{0}/{1}加载失败,请检查资源名称是否正确!", equipmentConfigData.id, equipmentConfigData.equipment_name));

                    equipment = equipmentObj.GetComponent<IEquipment>();

                    if (equipment == null)
                        throw new Exception(string.Format("未查询到装备IEquipment组件,请检查游戏物体{0}/{1}是否挂载装备脚本!",equipmentConfigData.projectName,equipmentConfigData.assetName));

                    equipment.OnLoaded(); 

                    break;

                case EquipmentType.Script:

                    Type type = AssemblyTools.GetType(equipmentConfigData.equipment_class_full_name);

                    if (type == null)
                        throw new Exception(string.Format("未查询到类:{0}", equipmentConfigData.equipment_class_full_name));

                    if (!typeof(IEquipment).IsAssignableFrom(type))
                        throw new Exception(string.Format("类型:{0}未实现装备IEquipment接口!", type.FullName));
                     
                    equipment = ClassObjectPoolManager.Load(type) as IEquipment;

                    break;
            }

            if (equipment != null) 
            {
                equipment.Equiper = null;
                equipment.EquipmentData = equipmentConfigData;
            }

            return equipment;
        }

      
        private static void DestroyEquipmentInternal(IEquipment equipment)
        {

            if (IsNull(equipment)) return;
             
            switch (equipment.EquipmentData.equipmentType)
            {
                case EquipmentType.Asset:
                    equipment.OnUnloaded();
                    Component component = equipment as Component;
                    if (component != null)
                        GameObjectLoader.UnLoad(component.gameObject);
                    break;
                case EquipmentType.Script:
                    ClassObjectPoolManager.Unload(equipment);
                    break;
            }

        }

        public static void DestroyEquipment(IEquipment equipment) 
        {
            if (IsNull(equipment.Equiper))
            {
                DestroyEquipmentInternal(equipment);
            }
            else
            {
                UnEquip(equipment, true);
            }
        }

        /// <summary>
        /// 创建并装备
        /// </summary>
        /// <param name="equipper">装备者(能够装备装备的游戏物体)</param>
        /// <param name="equipmentId">装备id</param>
        public static IEquipment CreateAndEquip(IEquippable equipper, int equipmentId) 
        {
            IEquipment equipment = CreateEquipment(equipmentId);
            Equip(equipper, equipment);
            return equipment;
        }

        #endregion
    }
     
}